<?php
/**
 * Discuz 风格模版引擎
 *
 */

class View_Discuz extends View_Abstract {

    /**
     * 构造函数
     *
     **/
    public function __construct(array $option = array()) {

        $option = array_merge(
                array(
                    'auto_update' => true,
                    'template_dir' => APP_PATH . '/template',
                    'template_ext' => 'html',
                    'compile_dir' => APP_PATH . '/tmp/template_c',
                    'compile_ext' => 'php',
                    'compile_prepend' => '',
                    'force_compile' => false,
                ), 
                $option
            );
        parent::__construct($option);
    }

    public static function _trimpath($path) {

        return str_replace(array('/', '\\', '//', '\\\\'), '/', $path);
    }

    public static function transamp($str) {
        $str = str_replace('&', '&amp;', $str);
        $str = str_replace('&amp;amp;', '&amp;', $str);
        $str = str_replace('\"', '"', $str);
        return $str;
    }

    public static function addquote($var) {
        return str_replace("\\\"", "\"", preg_replace("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $var));
    }

    public static function stripvtags($expr, $statement) {
        $expr = str_replace("\\\"", "\"", preg_replace("/\<\?\=(\\\$.+?)\?\>/s", "\\1", $expr));
        $statement = str_replace("\\\"", "\"", $statement);
        return $expr.$statement;
    }

    public static function stripscriptamp($s) {
        $s = str_replace('&amp;', '&', $s);
        return "<script src=\"$s\" type=\"text/javascript\"></script>";
    }

    private function _loadSubTemplate($info) {

        $tplName = $info[1];
        $tplfile = $this->_tplFile($tplName);
        return file_get_contents($tplfile);
    }

    private function _loadTemplate($info) {

        $tplName = $info[1];
        return '<?php include "' . str_replace('\\', '\\\\', $this->t($tplName)) . '"; ?>';
    }

    private function _tplFile($tplName) {

        return $this->_option['template_dir'] . '/' . $tplName . '.' . $this->_option['template_ext'];
    }

    private function _objFile($tplName) {

        return $this->_option['compile_dir'] . '/' . $tplName . '.' . $this->_option['compile_ext'];
    }

    private function t($tplName) {

        $tplfile = $this->_tplFile($tplName);
        $objfile = $this->_objFile($tplName);

        if($this->_option['force_compile'] || !is_file($objfile) ||
            (($this->_option['auto_update'] && @filemtime($objfile) < @filemtime($tplfile)))) {
                $this->parseTemplate($tplName);
        }
        return $objfile;
    }

    private function parseTemplate($tplName) {

        $tplfile = $this->_tplFile($tplName);
        $objfile = $this->_objFile($tplName);

        $nest = 5;
        $template = file_get_contents($tplfile);

        $varRegexp = "((\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*)";
        $constRegexp = "([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)";

        $template = preg_replace_callback("/[\n\r\t]*\{subtemplate\s+([a-z0-9_\/]+)\}[\n\r\t]*/is", array($this,'_loadSubTemplate'), $template);
        $template = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}", $template);
        $template = str_replace("{LF}", "<?=\"\\n\"?>", $template);
        $template = str_replace('_$', 'ESCAPED_DOLAR', $template);
        $template = preg_replace("/\{(\\\$[a-zA-Z0-9_\[\]\'\"\$\.\x7f-\xff]+)\}/s", "<?=\\1?>", $template);
        $template = preg_replace("/$varRegexp/es", "View_Discuz::addquote('<?=\\1?>')", $template);
        $template = preg_replace("/\<\?\=\<\?\=$varRegexp\?\>\?\>/es", "View_Discuz::addquote('<?=\\1?>')", $template);
        $template = preg_replace_callback("/[\n\r\t]*\{template\s+([a-z0-9_\/]+)\}[\n\r\t]*/is", array($this,'_loadTemplate'), $template);
        $template = preg_replace("/[\n\r\t]*\{eval\s+(.+?)\}[\n\r\t]*/ies", "View_Discuz::stripvtags('<?php \\1;?>','')", $template);
        $template = preg_replace("/[\n\r\t]*\{echo\s+(.+?)\}[\n\r\t]*/ies", "View_Discuz::stripvtags('<?php echo \\1;?>','')", $template);
        $template = preg_replace("/[\n\r\t]*\{([a-z0-9_]+)\s*\((.+?)\)\s*\}[\n\r\t]*/ies", "View_Discuz::stripvtags('<?php echo \\1(\\2);?>','')", $template);
        $template = preg_replace("/([\n\r\t]*)\{elseif\s+(.+?)\}([\n\r\t]*)/ies", "View_Discuz::stripvtags('\\1<?php } elseif(\\2) { ?>\\3','')", $template);
        $template = preg_replace("/([\n\r\t]*)\{else\}([\n\r\t]*)/is", "\\1<?php } else { ?>\\2", $template);

        for($i = 0; $i < $nest; $i++) {
            $template = preg_replace("/[\n\r\t]*\{loop\s+(\S+)\s+(\S+)\}[\n\r]*(.+?)[\n\r]*\{\/loop\}[\n\r\t]*/ies", "View_Discuz::stripvtags('<?php if(is_array(\\1)) { foreach(\\1 as \\2) { ?>','\\3<?php } } ?>')", $template);
            $template = preg_replace("/[\n\r\t]*\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}[\n\r\t]*(.+?)[\n\r\t]*\{\/loop\}[\n\r\t]*/ies", "View_Discuz::stripvtags('<?php if(is_array(\\1)) { foreach(\\1 as \\2 => \\3) { ?>','\\4<?php } } ?>')", $template);
            $template = preg_replace("/([\n\r\t]*)\{if\s+(.+?)\}([\n\r]*)(.+?)([\n\r]*)\{\/if\}([\n\r\t]*)/ies", "View_Discuz::stripvtags('\\1<?php if(\\2) { ?>\\3','\\4\\5<?php } ?>\\6')", $template);
        }

        $template = preg_replace("/\{$constRegexp\}/s", "<?=\\1?>", $template);
        $template = preg_replace("/ \?\>[\n\r]*\<\?php /s", " ", $template);
        $template = preg_replace("/<\?=(.*?)\?>/s", "<?php echo \\1;?>", $template);
        $template = preg_replace("/\"(http)?[\w\.\/:]+\?[^\"]+?&[^\"]+?\"/e", "View_Discuz::transamp('\\0')", $template);
        $template = preg_replace("/\<script[^\>]*?src=\"(.+?)\".*?\>\s*\<\/script\>/ise", "View_Discuz::stripscriptamp('\\1')", $template);
        $template = str_replace('ESCAPED_DOLAR', '$', $template);

        if(!is_dir(dirname($objfile))) {
            @mkdir(dirname($objfile), 0777, true);
        }
        file_put_contents($objfile, $this->_option['compile_prepend'].$template);
    }

    protected function _getCompiledFile($tpl) {

        return $this->t($tpl);
    }
}